package com.game.mine;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;

public class MinesweeperPanel extends JPanel {
    private static final int CELL_SIZE = 30; // 每个单元格的大小
    private static final int MARGIN = 5; // 单元格之间的边距
    private static final Color BG_COLOR = new Color(200, 200, 200); // 背景颜色
    private static final Color COVERED_COLOR = new Color(180, 180, 180); // 未揭示单元格的颜色
    private static final Color MINE_COLOR = Color.RED; // 地雷的颜色
    private static final Color FLAG_COLOR = Color.BLUE; // 标记的颜色

    private final int rows;
    private final int cols;
    private final int mines;
    private final boolean[][] mineField; // 雷区
    private final boolean[][] revealed; // 是否揭示
    private final boolean[][] flagged; // 是否标记
    private final int[][] adjacentMines; // 相邻地雷数
    private int remainingMines; // 剩余地雷数
    private boolean gameOver; // 游戏是否结束
    private MineCountChangeListener mineCountChangeListener;

    public interface MineCountChangeListener {
        void onMineCountChange(int remainingMines);
    }

    public void addMineCountChangeListener(MineCountChangeListener listener) {
        this.mineCountChangeListener = listener;
    }

    public int getRemainingMines() {
        return remainingMines;
    }

    public boolean isGameOver() {
        return gameOver;
    }

    public MinesweeperPanel(int rows, int cols, int mines) {
        this.rows = rows;
        this.cols = cols;
        this.mines = mines;
        this.mineField = new boolean[rows][cols];
        this.revealed = new boolean[rows][cols];
        this.flagged = new boolean[rows][cols];
        this.adjacentMines = new int[rows][cols];
        this.remainingMines = mines;
        this.gameOver = false;

        initializeMineField();
        calculateAdjacentMines();

        setPreferredSize(new Dimension(cols * (CELL_SIZE + MARGIN) + MARGIN, rows * (CELL_SIZE + MARGIN) + MARGIN));
        setBackground(BG_COLOR);
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (gameOver) return;

                int x = e.getX() / (CELL_SIZE + MARGIN);
                int y = e.getY() / (CELL_SIZE + MARGIN);

                if (x >= 0 && x < cols && y >= 0 && y < rows) {
                    if (e.getButton() == MouseEvent.BUTTON1) { // 左键点击
                        revealCell(x, y);
                    } else if (e.getButton() == MouseEvent.BUTTON3) { // 右键点击
                        toggleFlag(x, y);
                    }
                }
            }
        });
    }

    private void initializeMineField() {
        Random random = new Random();
        for (int i = 0; i < mines; i++) {
            int x, y;
            do {
                x = random.nextInt(cols);
                y = random.nextInt(rows);
            } while (mineField[y][x]);
            mineField[y][x] = true;
        }
    }

    private void calculateAdjacentMines() {
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                if (!mineField[y][x]) {
                    adjacentMines[y][x] = countAdjacentMines(x, y);
                }
            }
        }
    }

    private int countAdjacentMines(int x, int y) {
        int count = 0;
        for (int dy = -1; dy <= 1; dy++) {
            for (int dx = -1; dx <= 1; dx++) {
                if (dx == 0 && dy == 0) continue;
                int nx = x + dx;
                int ny = y + dy;
                if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && mineField[ny][nx]) {
                    count++;
                }
            }
        }
        return count;
    }

    private void revealCell(int x, int y) {
        if (flagged[y][x]) return; // 不能揭示已标记的单元格

        if (mineField[y][x]) {
            gameOver = true;
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    revealed[i][j] = true;
                }
            }
            JOptionPane.showMessageDialog(this, "游戏失败！");
        } else {
            revealed[y][x] = true;
            if (adjacentMines[y][x] == 0) {
                for (int dy = -1; dy <= 1; dy++) {
                    for (int dx = -1; dx <= 1; dx++) {
                        if (dx == 0 && dy == 0) continue;
                        int nx = x + dx;
                        int ny = y + dy;
                        if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && !revealed[ny][nx]) {
                            revealCell(nx, ny);
                        }
                    }
                }
            }
        }
        repaint();
        checkWinCondition();
    }

    private void toggleFlag(int x, int y) {
        if (revealed[y][x]) return; // 不能标记已揭示的单元格

        flagged[y][x] = !flagged[y][x];
        if (flagged[y][x]) {
            remainingMines--;
        } else {
            remainingMines++;
        }
        if (mineCountChangeListener != null) {
            mineCountChangeListener.onMineCountChange(remainingMines);
        }
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        drawBoard(g);
    }

    private void drawBoard(Graphics g) {
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                int x1 = x * (CELL_SIZE + MARGIN) + MARGIN;
                int y1 = y * (CELL_SIZE + MARGIN) + MARGIN;
                int x2 = x1 + CELL_SIZE;
                int y2 = y1 + CELL_SIZE;

                if (revealed[y][x]) {
                    if (mineField[y][x]) {
                        g.setColor(MINE_COLOR);
                        g.fillOval(x1, y1, CELL_SIZE, CELL_SIZE);
                    } else {
                        g.setColor(Color.WHITE);
                        g.fillRect(x1, y1, CELL_SIZE, CELL_SIZE);
                        if (adjacentMines[y][x] > 0) {
                            g.setColor(Color.BLACK);
                            g.drawString(Integer.toString(adjacentMines[y][x]), x1 + CELL_SIZE / 3, y1 + CELL_SIZE / 2);
                        }
                    }
                } else {
                    g.setColor(COVERED_COLOR);
                    g.fillRect(x1, y1, CELL_SIZE, CELL_SIZE);
                    if (flagged[y][x]) {
                        g.setColor(FLAG_COLOR);
                        g.drawLine(x1, y1, x2, y2);
                        g.drawLine(x2, y1, x1, y2);
                    }
                }
            }
        }
    }

    private void checkWinCondition() {
        boolean allRevealed = true;
        for (int y = 0; y < rows; y++) {
            for (int x = 0; x < cols; x++) {
                if (!revealed[y][x] && !mineField[y][x]) {
                    allRevealed = false;
                    break;
                }
            }
            if (!allRevealed) break;
        }
        if (allRevealed && !gameOver) {
            gameOver = true;
            JOptionPane.showMessageDialog(this, "过关！");
        }
    }
}